#include    "datetime.h"
#include    <ctime>

#ifdef _WIN32
#   include <Windows.h>
#endif

DateTime::DateTime() {
#ifdef _WIN32
    SYSTEMTIME now;
    GetLocalTime(&now);

    year = now.wYear;
    month = now.wMonth;
    day = now.wDay;
    hour = now.wHour;
    minute = now.wMinute;
    second = now.wSecond;
    millisec = now.wMilliseconds;
#else
    struct tm now;
    struct timespec detail;

    clock_gettime(CLOCK_REALTIME, &detail);
    localtime_r(&detail.tv_sec, &now);

    year = now.tm_year + 1900;
    month = now.tm_mon + 1;
    day = now.tm_mday;
    hour = now.tm_hour;
    minute = now.tm_min;
    second = now.tm_sec;
    millisec = detail.tv_nsec / 1000000;
#endif
}

int DateTime::Timestamp() const {
    struct tm local_time;

    local_time.tm_year = year - 1900;
    local_time.tm_mon = month - 1;
    local_time.tm_mday = day;
    local_time.tm_hour = hour;
    local_time.tm_min = minute;
    local_time.tm_sec = second;

    return (int)mktime(&local_time);
}

double operator-(const DateTime & l, const DateTime & r) {
    return (l.Timestamp() - r.Timestamp()) * 1000.0 + (l.millisec - r.millisec);
}

double Tick() {
#ifdef _WIN32
	static bool bInited = false;
	static double dFreq = 0;

	if (!bInited) {
		LARGE_INTEGER iPerfFreq;
		if (QueryPerformanceFrequency(&iPerfFreq)) {
			dFreq = 1.0 / iPerfFreq.QuadPart;
		} else {
			dFreq = 0;
		}
		bInited = true;
	}

	LARGE_INTEGER iCounter;
	if (!QueryPerformanceCounter(&iCounter)) return 0;
	return ((double)iCounter.QuadPart * dFreq * 1000);
#else
	struct timespec iClock;
	clock_gettime(CLOCK_MONOTONIC, &iClock);
	return iClock.tv_sec * 1000.0 + iClock.tv_nsec / 1000000.0;
#endif
}

std::string GMTime(time_t timestamp) {
    char buf[32] = { 0 };
    
#ifdef _MSC_VER
	struct tm gm;
    gmtime_s(&gm, &timestamp);
    strftime(buf, 32, "%a, %d %b %Y %H:%M:%S GMT", &gm);	
#else
	auto gm = gmtime(&timestamp);
    strftime(buf, 32, "%a, %d %b %Y %H:%M:%S GMT", gm);
#endif

    return std::string(buf);
}